package com.zhang.common.http;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * HttpClient
 *
 * @author zhangxin
 * @date 2021/6/18
 */
public final class HttpClient {
    private String host = "localhost";
    private int port = 80;
    private String encoding = null;
    private Map<String, String> cookies = new HashMap();
    private Map<String, String> session = new HashMap();
    private String cookiePath = null;
    private String cookieDomain = null;
    private String referer = null;

    public HttpClient() {
    }

    public HttpClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    private byte[] submit(URL action, String method, String value, String contentType) throws IOException {
        if(value == null) {
            value = "";
        }

        int nContentLength = value.length();
        byte[] byBuff = new byte[512];
        HttpURLConnection conn = null;
        InputStream is = null;
        OutputStream os = null;
        String forward = null;

        try {
            conn = (HttpURLConnection)action.openConnection();
            conn.setRequestMethod(method);
            conn.setRequestProperty("Accept", "*/*");
            if(this.referer != null) {
                conn.setRequestProperty("referer", this.referer);
            }

            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)");
            if(contentType != null && contentType.trim().length() > 0) {
                conn.setRequestProperty("Content-Type", contentType);
            } else {
                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            }

            if(nContentLength > 0) {
                conn.setRequestProperty("Content-Length", String.valueOf(nContentLength));
            }

            if(!this.cookies.isEmpty()) {
                String cookieString = this.getCookiesString(this.cookies);
                conn.setRequestProperty("Cookie", cookieString);
            }

            HttpURLConnection.setFollowRedirects(false);
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setDefaultUseCaches(false);
            conn.connect();
            if(nContentLength > 0) {
                os = conn.getOutputStream();
                if(this.encoding != null && this.encoding.trim().length() != 0) {
                    os.write(value.getBytes(this.encoding));
                } else {
                    os.write(value.getBytes());
                }

                os.flush();
            }

            Map<String, List<String>> mpHeader = conn.getHeaderFields();
            this.drawCookies(mpHeader);
            contentType = conn.getHeaderField("Content-Type");
            int nLen;
            if(this.encoding == null && contentType != null) {
                contentType = contentType.toUpperCase().trim();
                String tag = "CHARSET=";
                nLen = contentType.indexOf(tag);
                if(nLen > 0) {
                    this.encoding = contentType.substring(nLen + tag.length());
                }
            }

            forward = conn.getHeaderField("Location");
            is = conn.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            boolean var31 = false;

            while(true) {
                if((nLen = is.read(byBuff)) <= 0) {
                    byBuff = baos.toByteArray();
                    break;
                }

                baos.write(byBuff, 0, nLen);
            }
        } catch (IOException var27) {
            throw var27;
        } finally {
            if(os != null) {
                try {
                    os.close();
                } catch (Exception var26) {
                    ;
                }
            }

            if(is != null) {
                try {
                    is.close();
                } catch (Exception var25) {
                    ;
                }
            }

            if(conn != null) {
                try {
                    conn.disconnect();
                } catch (Exception var24) {
                    ;
                }
            }

        }

        if(forward == null) {
            return byBuff;
        } else {
            this.setReferer(action.getPath());
            action = new URL(action, forward);
            return this.get(action);
        }
    }

    private String getCookiesString(Map<String, String> map) {
        StringBuffer sb = new StringBuffer();

        String name;
        String value;
        for(Iterator it = map.keySet().iterator(); it != null && it.hasNext(); sb.append(name + "=" + value)) {
            name = (String)it.next();
            value = (String)map.get(name);
            if(sb.length() > 0) {
                sb.append("; ");
            }
        }

        if(sb.length() > 0) {
            sb.append("; ");
        }

        if(this.cookieDomain != null) {
            sb.append("domain=" + this.cookieDomain);
        }

        if(this.cookiePath != null) {
            sb.append("; path=");
            sb.append(this.cookiePath);
        }

        return sb.toString();
    }

    public void addCookie(String name, String value) {
        this.cookies.put(name, value);
    }

    public Map<String, String> getSession() {
        return this.session;
    }

    public void setReferer(String referer) {
        this.referer = referer;
    }

    public byte[] post(String address, Map<String, Object> params) throws IOException {
        String encodingTemp = this.getEncoding();
        StringBuffer sbParam = new StringBuffer();
        if(params != null && !params.isEmpty()) {
            Iterator it = params.keySet().iterator();

            while(it != null && it.hasNext()) {
                String name = (String)it.next();
                Object objValue = params.get(name);
                String[] values = null;
                if(objValue instanceof String) {
                    values = new String[]{(String)objValue};
                } else {
                    values = (String[])((String[])objValue);
                }

                for(int i = 0; values != null && i < values.length; ++i) {
                    String value = values[i] != null?URLEncoder.encode(values[i], encodingTemp):"";
                    if(sbParam.length() > 0) {
                        sbParam.append("&");
                    }

                    sbParam.append(name + "=" + value);
                }
            }
        }

        return this.post(address, sbParam.toString());
    }

    public byte[] post(String address, String value) throws IOException {
        return this.post(address, value, (String)null);
    }

    public byte[] post(String address, String value, String contentType) throws IOException {
        return this.submit(this.getURL(address), "POST", value, contentType);
    }

    public byte[] get(URL url) throws IOException {
        return this.submit(url, "GET", (String)null, (String)null);
    }

    public byte[] get(String address) throws IOException {
        return this.get(this.getURL(address));
    }

    private URL getURL(String address) throws MalformedURLException {
        if(address.trim().toLowerCase().startsWith("http://")) {
            return new URL(address);
        } else {
            String str = "http://" + this.host;
            if(this.port != 80) {
                str = str + ":" + this.port;
            }

            URL urlHost = new URL(str);
            return new URL(urlHost, address);
        }
    }

    private void drawCookies(Map<String, List<String>> mpHeader) {
        Iterator it = mpHeader.keySet().iterator();

        while(it != null && it.hasNext()) {
            String name = (String)it.next();
            if(name != null && name.startsWith("Set-Cookie")) {
                List<String> values = (List)mpHeader.get(name);

                for(int i = 0; values != null && i < values.size(); ++i) {
                    String cookieValue = (String)values.get(i);
                    if(cookieValue != null) {
                        String strLine = cookieValue.trim();
                        if(strLine.length() != 0) {
                            int n1 = strLine.indexOf("=");
                            name = strLine.substring(0, n1);
                            int n2 = strLine.indexOf(";");
                            String value = n2 > n1?strLine.substring(n1 + 1, n2):strLine.substring(n1 + 1);
                            this.cookies.put(name, value);
                            String tag;
                            if(this.cookieDomain == null) {
                                tag = "domain=";
                                n1 = strLine.indexOf(tag);
                                if(n1 >= 0) {
                                    n2 = strLine.indexOf(";", n1);
                                    this.cookieDomain = n2 > n1?strLine.substring(n1 + tag.length(), n2):strLine.substring(n1 + tag.length());
                                }
                            }

                            if(this.cookiePath == null) {
                                tag = "path=";
                                n1 = strLine.indexOf(tag);
                                if(n1 >= 0) {
                                    n2 = strLine.indexOf(";", n1);
                                    this.cookiePath = n2 > n1?strLine.substring(n1 + tag.length(), n2):strLine.substring(n1 + tag.length());
                                }
                            }

                            this.session.put(name, value);
                        }
                    }
                }
            }
        }

    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public String getEncoding() {
        return this.encoding != null?this.encoding:System.getProperty("file.encoding");
    }


}